#define USE_GENERICS

using System;
using System.Collections.Generic;
using System.Text;

namespace SharpMud.Terminal
{
    /// <summary>
    /// This module defines some basic functions for manipulating color values that are use for terminal interaction
    /// </summary>
	public class ColorUtility
	{
        /// <summary>
        /// Converts a SharpMud terminal color to a .NET console color
        /// </summary>
        public static System.ConsoleColor ToConsoleColor(TerminalColor terminalColor)
        {
            return (ConsoleColor)terminalColor;
        }

        /// <summary>
        /// Converts a .NET console color to a SharpMud terminal color
        /// </summary>
        public static TerminalColor ToTerminalColor(ConsoleColor consoleColor)
        {
            return (TerminalColor)consoleColor;
        }

        /// <summary>
        /// Converts a SharpMud terminal color to an RGB representation of said color
        /// </summary>
        public static int ToRGB(TerminalColor terminalColor)
        {
#if USE_GENERICS
            return ToRGB<TerminalColor>(terminalColor);
#else
            return ToRGB(typeof(TerminalColor),terminalColor);
#endif
        }

#if USE_GENERICS
        /// <summary>
        /// A generic version of ToRGB() that allows for code users to use their own color definitions
        /// </summary>
        public static int ToRGB<COLORTYPE>(COLORTYPE colorValue)
        {
            if (!typeof(COLORTYPE).IsEnum)
            {
                throw new ArgumentException("\"<COLORTYPE>\" must be an Enum type.");
            }
            foreach (System.Reflection.FieldInfo fi in (typeof(COLORTYPE)).GetType().GetFields())
            {
                if (fi.Name.ToLower().Trim() == colorValue.ToString().ToLower().Trim())
                {
                    foreach (RGBValueAttribute rva in fi.GetCustomAttributes(true))
                    {
                        return rva.RGB;
                    }
                    throw new InvalidOperationException("Unable to determine RGBValueAttribute for the specifed color.");
                }
            }
            throw new InvalidOperationException("Unable to find the specified color value in \"" + (typeof(COLORTYPE)).ToString() + "\" enum.");            
        }
#else
        public static int ToRGB(System.Type colorType, object colorValue)
        {
            if (!colorType.IsEnum)
            {
                throw new InvalidOperationException("\"colorType\" must be an Enum type.");
            }
            if(colorValue.GetType()!=colorType)
            {
                throw new InvalidOperationException("\"colorValue\" must be of the same type as \"colorType\"");
            }
            foreach (System.Reflection.FieldInfo fi in colorType.GetFields())
            {
                if (fi.Name.ToLower().Trim() == colorValue.ToString().ToLower().Trim())
                {
                    foreach (RGBValueAttribute rva in fi.GetCustomAttributes(true))
                    {
                        return rva.RGB;
                    }
                    throw new InvalidOperationException("Unable to determine RGBValueAttribute for the specifed color.");
                }
            }
            throw new InvalidOperationException("Unable to find the specified color value in \"" + colorType.ToString() + "\" enum.");            
        }
#endif

        /// <summary>
        /// Converts a .NET console color to an RGB representation of said color
        /// </summary>
        public static int ToRGB(ConsoleColor consoleColor)
        {
            return ToRGB(ToTerminalColor(consoleColor));
        }

        internal static int RGB(byte r, byte g, byte b)
        {
            return ((int)b) + ((int)(g * byte.MaxValue)) + ((int)(b * byte.MaxValue * byte.MaxValue));
        }
	}

    /// <summary>
    /// An enum that defines some constants used to define RGB-triplet constants elsewhere
    /// </summary>
    internal enum HueIntensity : byte
    {
        Highest = 255,
        High = 192,
        Medium = 127,
        Low = 63,
        None = 0
    }

    /// <summary>
    /// A nifty attribute used to mark enum-based color definitions with their RGB equivalencies
    /// </summary>
    [AttributeUsage(AttributeTargets.Field)]
    internal class RGBValueAttribute : System.Attribute
    {
        private byte _Red;
        private byte _Green;
        private byte _Blue;

        protected RGBValueAttribute()
        {
        }

        public RGBValueAttribute(byte red, byte green, byte blue)
        {
            _Red = red;
            _Green = green;
            _Blue = blue;
        }

        public RGBValueAttribute(HueIntensity red, HueIntensity green, HueIntensity blue)
            :this((byte)red,(byte)green,(byte)blue)
        {
        }

        public byte Red { get { return _Red; } }
        public byte Green { get { return _Green; } }
        public byte Blue { get { return _Blue; } }

        public int RGB
        {
            get
            {
                return ColorUtility.RGB(_Red, _Green, _Blue);
            }
        }
    }
}
